אף אחד לא מפתיע שהדוקומנטציה של פייפאל מסובכת, ארוכה ולא ניתנן להבנה. אחרי הכל, stripe עשו אחלה סטארטאפ על העובדה שלהתקין קבלת תשלומים עם פייפאל באתר זה מקצוע בפני עצמו. למזלנו, ב-PHP כבר כתבו הכל, מה שמשאיר לנו משימה קצת יותר פשוטה: לקחת מחלקה מוכנה ולהבין איך להשתמש בה.
IPN — Instant Payment Notification
בתמונה הכללית רק ארבעה שלבים מפרידים בינך לבין הכסף במהלך התקשורת עם פייפאל.
בשלב הראשון הלקוח לוחץ על כפתור הקניה באתר ומועבר לאתר פייפאל, בו הוא מבצע את התשלום. לאחר סיום התשלום המשתמש יוחזר לאתר ותוכל להציג לו הודעת תודה.
בשלב השני, לאחר שפייפאל יגבו את הכסף מהלקוח, השרת שלהם ישלח הודעת POST לשרת שלך. זוהי ההודעה המיידית על ביצוע התשלום (ipn). ההודעה הזו כוללת את כל המידע הדרוש לגבי התשלום שיתקבל ואפילו יותר מזה. למשל, היא כוללת את שם המוצר שנקנה, המחיר ששולם והמטבע ששימש לביצוע התשלום.
בשלב הבא עליך לאמת את מקור ההודעה, אם אתה רוצה להיות בטוח שהיא נשלחה מפייפאל ולא מאיזה סטודנט עם פידלר. בשלב הזה השרת שלך שולח לשרת של פייפאל הודעה לאימות: האם בוצע תשלום בסכום כזה, עבור מוצר כזה וכל שאר הפרטים?
בתגובה תקבל הודעה בסגנון VERIFIED או INVALID, שאכן ההודעה המקורית על קבלת תשלום נשלחה מפייפאל ולא ממישהו אחר. רק אחרי השלב הזה תוכל לשלוח למשתמש את המוצר, לעדכן לפרימיום במסד ולהיות בטוח שאתה בדרך להיות המיליונר הבא.
שלב א. כמה זה עולה?
בשלב הראשון המשתמש בוחר את המוצר(ים) באתר שלך, לוחץ על כפתור התשלום ומועבר לאתר paypal. כדי שהכישוף הזה יעבוד נצטרך להוסיף לסיר עוד כמה מרכיבים: מי המשתמש, מה המוצר ומה סכום התשלום שעלינו לגבות. כל אלו מגיעים אל פייפאל כחלק מהטופס שנשלח על ידי המשתמש ברגע לחיצת כפתור הקניה.
את הטופס עצמו אנחנו לא הולכים ליצור בעצמנו, אלא להכין דרך פייפאל. בשביל לעשות את זה - כנס לחשבון הפייפאל שלך וגש אל My Account -> Profile -> More Options
בחירה ב- My Selling Tools בתפריט מצד שמאל תוביל אותך לעמוד הגדרות המכירות שלך. הסעיף הראשון ברשימה Paypal buttons הוא זה שמעניין אותנו כרגע, לצורך יצירת טפסים וכפתורי קניה משלנו. אני ממליץ לעבור בזמנך הפנוי גם על הסעיפים האחרים, כמו למשל מה שם העסק שיופיע בדו"ח כרטיס האשראי החודשי של הלקוח.
הקישור מצד ימין Create New Button יוביל אותך למסך יצירת הכפתור. אני בטוח שאם הסתדרת עם לבנות אתר ולארגן מוצר, אתה תסתדר עם ליצור כפתור. אמנם יש כמה שדות שכדאי לשים לב אליהם:
השדות item name ו-item id ישמשו אותנו לאחר האימות כדי לדעת איזה מוצר נקנה. ה-id איננו שדה חובה ואפשר להסתדר רק עם השם של המוצר, כול עוד אתה נותן שמות ייחודיים לכל מוצר שאתה מוכר.
אני ממליץ לא להשאיר ריקים את השדות עם העמודים שאליהם יועבר המשתמש בסיום הקניה. בעמוד הזה תוכל לשים סקריפט ajax קטן שבודק כל 5 שניות האם התקבל ואומת תשלום עבור אותו משתמש ואם כן, להציג לו הודעה משמחת עם קישור להורדה של המוצר.
השדה האחרון כולל את הכתובת notify_url, הכתובת אליה paypal ישלחו בקשות ipn; אל תשכח להוסיף אחת כזאת.
הוספת שדות משלך לטופס
בסיום התהליך תקבל קוד html של טופס. את הטופס תוכל למקם באתר. השדה הנראה היחידי בטופס שהמשתמש יראה על המסך הוא הכפתור. שאר המידע לגבי הטופס, כמו מחיר, מטבע ושם המוצר נשמרים בשרת של פייפאל ואין לנו צורך לגעת בהם.
מצד שני, הטופס לא כולל משהו חשוב אחר, וזהו מזהה של המשתמש שביצע את התשלום. בלעדיו לא נוכל לדעת מי ביצע את התשלום וצריך לקבל את המוצר. לתקן את המצב אפשר על ידי הוספת שדה משלנו לטופס:
<input name="custom" value="<?=$userid?>" type="hidden">
השדה custom יכלל בבקשת ה-ipn ולפיו נוכל לתת את ההרשאות למשתמש המתאים.
טיפול ואימות בקשות paypal ipn - קבלת תשלומים באתר
עברת בהצלחה את החלק הראשון בתהליך, יצרת את הטופס, הלקוחות הוציאו את כרטיסי האשראי והשרת שלך מפוצץ בבקשות ipn של תשלומים נכנסים. מה עושים איתם? הדבר הראשון שעושים - רושמים. רושמים הכל. כל פיפס שקשור לתשלומים נכנס ללוגים, כדי שאתה ושירות הלקוחות שלך לא תצטרכו לעבוד שעות נוספות.
אחרי שלא שכחת לרשום כל דבר ללוג, את הודעות ה-ipn כדאי גם לאמת, כדי לוודא שהם הגיעו מפייפאל ולא מהחלל החיצון. אתה יכול לעשות את זה בעמך, או שאתה יכול להשתמש במחלקה מוכנה PHP-PayPal-IPN. את המחלקה אפשר להוריד מפה או להתקין דרך composer.
המחלקה הזו, מאחורי הקלעים, תבדוק את הקלט, תייצר ותשלח בקשה לשרת של פייפאל, תבדוק את התשובה של פייפאל ותחזיר לך בסופו של דבר true או false, אך עדיין תשאיר בצד כמה בדיקות חשובות. קודם כל עליך לוודא שהמחיר ששולם הוא הסכום שאתה מצפה לקבל, שהמטבע הוא שקל ישראלי חדש וזוהי הודעה אמיתית שעדיין לא טיפלת בה.
אגב, פייפאל ידאג להמשיך לשלוח לך הודעות IPN עד אשר אתה תנסה לאמת אותם בהצלחה, ככה שאם אחת הבדיקות נכשלה, המסד נפל או לשרת שלך נגמרה הסוללה — פייפאל ימשיכו לשלוח לך את אותה הודעות IPN, עד שתקבל אותה.
קוד לבדיקת תשלומים באתר עם paypal
אחרי החימוש בספריית php-paypal-ipn הקוד הבא יעשה את העבודה:
$items = [
'iceCream' => 42.90
'premium' => 600
];
$postData = $_POST;
$ipnListener = new IpnListener('paypal_api_certificate.crt');
$ipnListener->requirePostMethod();
$verified = $ipnListener->processIpn($postData);
if($verified)
{
if(checkDataValid($postData, $items))
{
// good, item was paid
$user = $postData['custom'];
}
}
function checkDataValid(array $postData, $items)
{
if($postData['payment_status'] != 'Completed'){
return false;
}
if(!isset($items[$postData['item_name']])
throw new \Exception("Bought an unknown item?!");
if($postData['receiver_email'] !== '[email protected]') // !!!!!!!!!!! money was tranfered to your account
throw new \Exception("Receiver email not matching");
if ($postData['mc_currency'] !== 'ILS') // paid in Israeli Shekels
throw new \Exception("Received payment not in expected currency");
$itemPrice = $items[$postData['item_name']];
if(floatval($postData['mc_gross']) !== floatval($itemPrice)) // paid the correct price
throw new \Exception("Amount does not match. Expected <".floatval($postData['mc_gross']).'>, got <'.floatval($itemPrice).'>');
return true;
}
'iceCream' => 42.90
'premium' => 600
];
$postData = $_POST;
$ipnListener = new IpnListener('paypal_api_certificate.crt');
$ipnListener->requirePostMethod();
$verified = $ipnListener->processIpn($postData);
if($verified)
{
if(checkDataValid($postData, $items))
{
// good, item was paid
$user = $postData['custom'];
}
}
function checkDataValid(array $postData, $items)
{
if($postData['payment_status'] != 'Completed'){
return false;
}
if(!isset($items[$postData['item_name']])
throw new \Exception("Bought an unknown item?!");
if($postData['receiver_email'] !== '[email protected]') // !!!!!!!!!!! money was tranfered to your account
throw new \Exception("Receiver email not matching");
if ($postData['mc_currency'] !== 'ILS') // paid in Israeli Shekels
throw new \Exception("Received payment not in expected currency");
$itemPrice = $items[$postData['item_name']];
if(floatval($postData['mc_gross']) !== floatval($itemPrice)) // paid the correct price
throw new \Exception("Amount does not match. Expected <".floatval($postData['mc_gross']).'>, got <'.floatval($itemPrice).'>');
return true;
}
אני לא חושב שיש צורך להסביר את הקוד הזה, למעט הפרמטר של הקונסטקטור של מחלקת IpnListener. היות שהתקשורת בין השרת שלך לבין השרת של פייפאל עומדת להתבצע דרך https, יכול להיות ש-curl בשרת שלך ידרוש את התעודה של שרת הפייפאל. את קובץ ה-crt אפשר להוריד מפה או מפה. את הנתיב לקובץ מצפה לקבל הקונסטרקטור של מחלקת ipnListener.
שים לב להכניס את הערכים המתאימים בשדות של הבדיקות: שם מוצר תואם לזה שרשמת בטופס יצירת כפתור פייפאל, אימייל שאיתו אתה רשום בפייפאל בתור מקבל הכסף ומטבע תואם לזה שברצונך לקבל. בנוסף, אזכיר שוב לרשום כל שלב וכל פיסת מידע ללוגים, למקרה שמשהו ילך לא כמו שצריך.
לראות איך זה קורה כרגע ב-phpguide אפשר בקוד המקור של האתר.
בדיקות ו-sandbox
את כל התהליך אפשר ואפילו צריך לבדוק לפני. בשביל בדיקות פייפאל מציעה שירות ארגז חול למשחקים. צורת העבודה שלו זהה לחלוטין לזו של הסליקה הרגילה, רק שאין צורך להזין כרטיס אשראי וגם אין מעבר כסף מחשבון אחד לחשבון אחר. כדי לנסות את המערכת בסביבת בדיקות עליך ליצור שני משתמשים חדשים באתר הבדיקות של פייפאל: https://www.sandbox.paypal.com ולבצע שוב את תהליך יצירת הכפתור והטפסים עם אחד מהם (המוכר). המשתמש השני ישמש אותך כדי לבצע את הקניה. בסופו של דבר שני הטפסים (האמיתי והבדיקות) שיהיו בידך יהיו שונים זה מזה רק בכתובת שאליה נשלח הטופס ובשדה hosted_button_id.
הבדל נוסף אחר בשלב הבדיקות יהיה לומר למערכת האימות לבצע את האימות מול סביבת הבדיקות של פייפאל, אחרת כל ניסיונות האימות היכשלו. מחלקת האימות שלנו כוללת מאפיין מיוחד בשביל זה שתוכל להציב כ-true או כ-false ואימות בקשת ה-ipn יתבצע מול הסביבה המתאימה:
$listener = new IpnListener();
$listener->use_sandbox = true;
$listener->use_sandbox = true;
בזה מסתכם עניין קבלת התשלומים באתר באמצעות פייפאל ו-php. בהצלחה במכירות.
תגובות לכתבה:
כמה דברים, PayPal IPN זאת כבר אפשרות פחות עדיפה לקבלת תשלום לאתר, היא ישנה ופחות דינמית מExpress Checkout (שאיתה דרך הסקריפט אתה יכול לקבוע גובהה תשלום וכו'.) וחוץ מזה, PP הוציאו REST API שאיתו השמיים הם הגבול..
תודה ושבת שלום D:
מדריך נחמד, רק עדיין לא הבנתי לעזאזל איפה בעצם שמים ב - IPN את כתובת האימייל של מקבל התשלום?
אתה לא מגדיר אמייל, דרך החשבון PP שלך אתה יוצר "עסקה\העברה" ולה יש ערך זיהוי (hosted_button_id) יחודי, ככה PP יודע את לאיזה חשבון להעביר את הכסף..